package resource

import (
	"fmt"
	"k8s.io/klog"
	"kubeconsole/client/informers"
	"kubeconsole/handlers/params"
	"kubeconsole/models"
	"kubeconsole/models/resources/v1alpha2"
	"kubeconsole/models/resources/v1alpha2/clusterrole"
	"kubeconsole/models/resources/v1alpha2/configmap"
	"kubeconsole/models/resources/v1alpha2/cronjob"
	"kubeconsole/models/resources/v1alpha2/hpa"
	"kubeconsole/models/resources/v1alpha2/namespace"
	"kubeconsole/models/resources/v1alpha2/node"
	"kubeconsole/models/resources/v1alpha2/persistentvolumeclaim"
	"kubeconsole/models/resources/v1alpha2/pod"
	"kubeconsole/models/resources/v1alpha2/role"
	"kubeconsole/models/resources/v1alpha2/storageclass"
	"kubeconsole/utils/sliceutil"
)

type ResourceGetter struct {
	resourcesGetters map[string]v1alpha2.Interface
}

func (r ResourceGetter) Add(resource string, getter v1alpha2.Interface) {
	if r.resourcesGetters == nil {
		r.resourcesGetters = make(map[string]v1alpha2.Interface)
	}
	r.resourcesGetters[resource] = getter
}

func NewResourceGetter(factory informers.InformerFactory) *ResourceGetter {
	resourceGetters := make(map[string]v1alpha2.Interface)

	resourceGetters[v1alpha2.ConfigMaps] = configmap.NewConfigmapSearcher(factory.KubernetesSharedInformerFactory())
	resourceGetters[v1alpha2.CronJobs] = cronjob.NewCronJobSearcher(factory.KubernetesSharedInformerFactory())
	resourceGetters[v1alpha2.HorizontalPodAutoscalers] = hpa.NewHpaSearcher(factory.KubernetesSharedInformerFactory())
	resourceGetters[v1alpha2.ClusterRoles] = clusterrole.NewClusterRoleSearcher(factory.KubernetesSharedInformerFactory())
	resourceGetters[v1alpha2.Roles] = role.NewRoleSearcher(factory.KubernetesSharedInformerFactory())

	resourceGetters[v1alpha2.PersistentVolumeClaims] = persistentvolumeclaim.NewPersistentVolumeClaimSearcher(factory.KubernetesSharedInformerFactory(), factory.SnapshotSharedInformerFactory())
	resourceGetters[v1alpha2.Pods] = pod.NewPodSearcher(factory.KubernetesSharedInformerFactory())
	resourceGetters[v1alpha2.Nodes] = node.NewNodeSearcher(factory.KubernetesSharedInformerFactory())
	resourceGetters[v1alpha2.Namespaces] = namespace.NewNamespaceSearcher(factory.KubernetesSharedInformerFactory())
	resourceGetters[v1alpha2.StorageClasses] = storageclass.NewStorageClassesSearcher(factory.KubernetesSharedInformerFactory(), factory.SnapshotSharedInformerFactory())
	/*	resourceGetters[v1alpha2.Workspaces] = workspace.NewWorkspaceSearcher(factory.KubeSphereSharedInformerFactory())
		resourceGetters[v1alpha2.Applications] = application.NewApplicationSearcher(factory.ApplicationSharedInformerFactory())*/

	return &ResourceGetter{resourcesGetters: resourceGetters}

}

var (
	clusterResources = []string{v1alpha2.Nodes, v1alpha2.Workspaces, v1alpha2.Namespaces, v1alpha2.ClusterRoles, v1alpha2.StorageClasses, v1alpha2.S2iBuilderTemplates}
)

func (r *ResourceGetter) GetResource(namespace, resource, name string) (interface{}, error) {
	if searcher, ok := r.resourcesGetters[resource]; ok {
		resource, err := searcher.Get(namespace, name)
		if err != nil {
			klog.Errorf("resource %s.%s.%s not found: %s", namespace, resource, name, err)
			return nil, err
		}
		return resource, nil
	}
	return nil, fmt.Errorf("resource %s.%s.%s not found", namespace, resource, name)
}

func (r *ResourceGetter) ListResources(namespace, resource string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
	items := make([]interface{}, 0)
	var err error
	var result []interface{}

	// none namespace resource
	if namespace != "" && sliceutil.HasString(clusterResources, resource) {
		err = fmt.Errorf("resource %s is not supported", resource)
		klog.Errorln(err)
		return nil, err
	}

	if searcher, ok := r.resourcesGetters[resource]; ok {
		result, err = searcher.Search(namespace, conditions, orderBy, reverse)
	} else {
		err = fmt.Errorf("resource %s is not supported", resource)
		klog.Errorln(err)
		return nil, err
	}

	if err != nil {
		klog.Errorln(err)
		return nil, err
	}

	if limit == -1 || limit+offset > len(result) {
		limit = len(result) - offset
	}

	items = result[offset : offset+limit]

	return &models.PageableResponse{TotalCount: len(result), Items: items}, nil
}
